﻿#This script generates an uptime report and works only on Windows Server.
#Windows 7 eventlog is not compatible
######################
#Author: Nicolas Vinot
#Version 1.0
######################
#Parameters: If not specified, the default values are: local computer and 90 days of events
Param ([Parameter(Mandatory=$False, Position = 1)] [String]$HostName = $env:computerName,
       [Parameter(Mandatory=$False, Position = 2)] [Single]$EventsPeriod = 90)
#Initialization
[Array]$EventsList = @()
[Array]$LastBoot = @()
[Single]$MTBRTemp = 0
[Single]$TotalReboot = 0
[Single]$UnexpectedShutdownCount = 0
[Double]$AvailabilityRate = 0
[TimeSpan]$MTBReboot = 0
[TimeSpan]$TotalUptime = 0
[TimeSpan]$TotalDowntime = 0
[DateTime]$EndUpPeriod  = 0
[Datetime]$EventsAfter = (Get-Date).AddDays(-$EventsPeriod)
[DateTime]$StartUpPeriod = 0

Write-Host "Uptime Report for:" $HostName
Write-Host
If (!(Test-Connection -ComputerName $HostName -Count 1 -Quiet))
    {Write-Host "Host" $HostName "unreachable"
    Exit}
#Get events from logs
$EventsList = (Get-EventLog -ComputerName $HostName -LogName System -After $EventsAfter | where {$_.eventID -eq 6005 -or $_.eventID -eq 6006 -or $_.eventID -eq 6008} |  Select-Object Index, TimeGenerated, EventID )

#Check if Eventslist.Count is even to keep accuracy when Eventlog is purged
$EventsCount = $EventsList.Count
#If the Eventlog is empty, a start event is created
If ($EventsCount -eq 0)
    {
    #Create the Start event
    $LastBoot = Get-CimInstance Win32_OperatingSystem -ComputerName $HostName | Select-Object LastBootUpTime
    $NewEvent = @()
    $NewEvent = "" | Select Index, TimeGenerated, EventID
    $NewEvent.Index = 2
    $NewEvent.TimeGenerated = $LastBoot.LastBootUpTime
    $NewEvent.EventID = 6005
    $EventsList += $NewEvent
    }
#Refreshing Event count to simplify cases
$EventsCount = $EventsList.Count
#If the Eventlog only contains a start event creating the Stop event
#The TimeGenerated stop event is set equal to the TimeGenerated Start event to generate a 0 downtime
If ($EventsCount -eq 1)
    {
    $NewEvent = @()
    $NewEvent = "" | Select Index, TimeGenerated, EventID
    $NewEvent.Index = 1
    $NewEvent.TimeGenerated = $EventsList.TimeGenerated[0]
    $NewEvent.EventID = 6006
    $EventsList += $NewEvent
    }

If ([Bool]!($EventsCount%2))
    {$TotalEvents = $EventsCount}
Else
    {$TotalEvents = $EventsCount - 1}
$EventIndex = 0
While ($EventIndex -lt $TotalEvents)
    {
    [DateTime]$StartUpPeriod = 0
    [DateTime]$EndUpPeriod  = 0
    #Loading Start event
    $StartUpPeriod = $EventsList.TimeGenerated[$EventIndex]
    $EventIndex++
    #Loading Stop event
    #Bluescreen counter and Find ltest 4 events to determine last uptime
    If ($EventsList.EventID[$EventIndex] -eq 6008)
        {
        $4thLastIndex = $EventsList.Index[$EventIndex] - 4
        $4thLastEvent = Get-EventLog -ComputerName $HostName -LogName System -Index $4thLastIndex |  Select-Object Index, TimeGenerated, EventID
        $EndUpPeriod = $4thLastEvent.TimeGenerated[0]
        $UnexpectedShutdownCount++
        }
    Else
        {$EndUpPeriod = $EventsList.TimeGenerated[$EventIndex]}
    #Common section to Start/Stop events
    #Reboot counter
    $TotalReboot ++
    #
    $TotalDowntime += $StartUpPeriod - $EndUpPeriod
    $ThisPeriod = $StartUpPeriod - $EndUpPeriod
    If ($ThisPeriod -eq 0)
        {Write-Host "No downtime"}
    Else
        {Write-Host "The system was down from the" $EndUpPeriod "to the" $StartUpPeriod " Duration:" $ThisPeriod}
    $EventIndex++
    }
#Calculation section
#The last $StartUpPeriod contains the last known start date
$TotalUptime = (Get-Date) - $StartUpPeriod
$CurrentUpTime = (Get-Date) - $EventsList.TimeGenerated[0]
$TotalAvailability = ($TotalUptime - $TotalDowntime)
$AvailabilityRate = ($TotalAvailability.TotalMinutes / $TotalUptime.TotalMinutes)
$MTBRTemp = $TotalUpTime.TotalMinutes / $TotalReboot
$MTBRTemp = [Math]::Round($MTBRTemp)
$MTBReboot = New-TimeSpan -Minutes $MTBRTemp
#Layout
Write-Host
Write-Host "Since " $StartUpPeriod.ToString("dd\/MM\/yy")
Write-Host "Current Uptime" $CurrentUptime.Days "Days" $CurrentUptime.Hours "Hours" $CurrentUpTime.Minutes "Min"
Write-Host
Write-Host "On the considered period of" $EventsPeriod "Days, System Availability: " $AvailabilityRate.ToString("0.0000%")
Write-Host
Write-Host "  - Total Uptime:" $TotalUptime.ToString("dd\d\ hh\h\:mm\m\:ss\s")
Write-Host "  - Total Downtime: " $TotalDowntime
Write-Host "  - Total Bluescreens: " $UnexpectedShutdownCount
Write-Host "  - Total Reboots:" $TotalReboot
Write-Host "  - Mean Time Between Reboots: " $MTBReboot.TotalDays.ToString("0.00 Days")